package com.hilaver.dzmis.exhibition.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Blob;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.hibernate.Hibernate;

import com.hilaver.dzmis.exhibition.utils.Constants;
import com.hilaver.dzmis.exhibition.utils.StringUtils;

public abstract class AbstractBaseServlet extends HttpServlet implements
		javax.servlet.Servlet {

	public final static int MAX_UPLOAD_FILE_SIZE = 2 * 1024 * 1024;

	public final static int MAX_UPLOAD_FILE_CACHE = 4 * 1024 * 1024;

	public final static String UPLOAD_TEMP_DIR = "/_temp";

	public static String UPLOAD_TEMP_REAL_DIR;

	public final static int ACTOIN_GET_ALL_PAGINATION = 0; // "getAllPagination";
	public final static int ACTION_EDIT = 1; // "edit";
	public final static int ACTION_DELETE = 2; // "delete";
	public final static int ACTION_GET = 3; // "get one";
	public final static int ACTION_GET_ALL_PAGINATION_FILTER = 4; // "getAllPagination
	// filter";
	public final static int ACTION_GET_ALL = 5; // "getAll";
	
	public final static int ACTION_GET_ALL_FROM_CHART = 6; // "getAll";

	public final static int ACTION_GET_WITH_DESCRIPTION = 11; // "get one with

	protected int start;
	protected int limit;
	protected int page;
	protected String dir;
	protected String sort;
	protected String[] filters;
	protected Map filterTypeMap;
	protected Map filterValueMap;
	protected Map filterFieldMap;

	protected String fullName;
	protected String simpleName;
	protected int action;
	protected Integer id;

	protected Object obj;

	public AbstractBaseServlet() {

	}

	protected void setPaginationParam(ServletRequest request) {
		String start = request.getParameter("start");
		String limit = request.getParameter("limit");
		String dir = request.getParameter("dir");
		String sort = request.getParameter("sort");
		if (start == null) {
			this.start = 0;
		} else {
			this.start = Integer.parseInt(start);
		}
		if (limit == null) {
			this.limit = Constants.PAGE_SIZE;
		} else {
			this.limit = Integer.parseInt(limit);
		}
		this.page = this.start / this.limit + 1;
		if (dir == null) {
			this.dir = Constants.ORDER_DESC;
		} else {
			this.dir = dir;
		}
		if (sort == null) {
			this.sort = "id";
		} else {
			this.sort = sort;
		}
	}

	protected void setFilterParam(HttpServletRequest request) throws Exception {
		Locale locale = (Locale) request.getSession().getAttribute(
				Constants.SESSION_LOCALE);
		Map paramMap = request.getParameterMap();
		Set ketSet = paramMap.keySet();
		this.filterFieldMap = new HashMap();
		this.filterValueMap = new HashMap();
		this.filterTypeMap = new HashMap();
		for (Iterator iterator = ketSet.iterator(); iterator.hasNext();) {
			String name = (String) iterator.next();
			if (name.startsWith("filter")) {
				String[] tmp = name.split("\\[");
				String indexStr = tmp[1];

				int index = Integer.parseInt(indexStr.substring(0, indexStr
						.indexOf("]")));
				if (tmp.length == 4) {
					if (tmp[3].equals("type]")) {
						filterTypeMap.put(index, request.getParameter(name));
					}
					if (tmp[3].equals("value]")) {
						filterValueMap.put(index, request.getParameter(name));
					}
				}
				if (tmp.length == 3) {
					if (tmp[2].equals("field]")) {
						filterFieldMap.put(index, request.getParameter(name));
					}
				}
			}
		}
		if (filterTypeMap.size() == 0) {
			this.filters = null;
			return;
		}
		this.filters = new String[filterTypeMap.size()];
		for (int i = 0; i < filterTypeMap.size(); i++) {
			if (filterTypeMap.get(i).equals("string")) {
				this.filters[i] = filterFieldMap.get(i) + " like '%"
						+ filterValueMap.get(i) + "%'";
			} else if (filterTypeMap.get(i).equals("list")) {
				String field = (String) filterFieldMap.get(i);
				System.out.println(field + ": " + filterFieldMap.get(i));
			}
		}
	}

	protected void setAction(HttpServletRequest request) throws Exception {
		String action = request.getParameter("action");
		if (!StringUtils.isEmpty(action)) {
			this.action = Integer.parseInt(action);
		} else {
			this.action = 0;
		}
	}

	protected void setId(HttpServletRequest request) {
		if (!"".equals(request.getParameter("id"))
				&& request.getParameter("id") != null) {
			this.id = Integer.parseInt(request.getParameter("id"));
		} else {
			this.id = null;
		}

	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		this.doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		PrintWriter writer = response.getWriter();
		try {
			String outputStr = execute(request);
			if (this.action == ACTION_EDIT) {
				response.setContentType(Constants.HTML_RESPONSE_TYPE);
			}
			writer.write(outputStr);
		} catch (Exception e) {
			writer.print(e.getMessage());
			e.printStackTrace();
		}
		writer.close();
	}

	protected String execute(HttpServletRequest request) throws Exception {
		this.setAction(request);

		Object serviceObj = this.getService();
		Method method = null;
		String rtn = "";

		switch (this.action) {
		case ACTOIN_GET_ALL_PAGINATION: // "getAllPagination";
			this.setPaginationParam(request);
			method = serviceObj.getClass().getMethod("getAllPagination",
					new Class[] { int.class, String.class, String.class });// int
			// page,
			// String
			// sort,
			// String
			// order
			rtn = (String) method.invoke(serviceObj, new Object[] { this.page,
					this.sort, this.dir });
			break;
		case ACTION_EDIT: // "edit";
			this.fillObj(request);
			method = serviceObj.getClass().getMethod("edit",
					new Class[] { Object.class });
			rtn = (String) method.invoke(serviceObj, new Object[] { this.obj });
			break;
		case ACTION_DELETE: // "delete";
			this.setId(request);
			method = serviceObj.getClass().getMethod("delete",
					new Class[] { int.class });
			rtn = (String) method.invoke(serviceObj, new Object[] { this.id });
			break;
		case ACTION_GET: // "get one"
			this.setId(request);
			method = serviceObj.getClass().getMethod("get",
					new Class[] { int.class });
			rtn = (String) method.invoke(serviceObj, new Object[] { this.id });
			break;
		case ACTION_GET_ALL_PAGINATION_FILTER: // "getAllPagination filter"
			this.setPaginationParam(request);
			this.setFilterParam(request);
			method = serviceObj.getClass().getMethod(
					"getAllPagination",
					new Class[] { int.class, String.class, String.class,
							String[].class });// int page, String sort, String
			// order
			rtn = (String) method.invoke(serviceObj, new Object[] { this.page,
					this.sort, this.dir, this.filters });
			break;
		case ACTION_GET_ALL:
			this.setPaginationParam(request);
			method = serviceObj.getClass().getMethod("getAll",
					new Class[] { String.class, String.class });// String sort,
			// String
			// order
			rtn = (String) method.invoke(serviceObj, new Object[] { this.sort,
					this.dir });
			break;
		}

		return rtn;
	}

	private Object getService() throws Exception {
		String serviceClassName = "com.hilaver.dzmis.exhibition.service."
				+ this.simpleName + "Service";
		Object serviceObj = Class.forName(serviceClassName).newInstance();
		return serviceObj;
	}

	protected void fillObj(HttpServletRequest request) throws Exception {
		this.obj = Class.forName(this.fullName).newInstance();
		Field[] fields = this.obj.getClass().getDeclaredFields();
		if (ServletFileUpload.isMultipartContent(request)) {
			DiskFileItemFactory factory = new DiskFileItemFactory();
			factory.setSizeThreshold(MAX_UPLOAD_FILE_CACHE);
			factory.setRepository(new File(getServletContext().getRealPath(
					UPLOAD_TEMP_DIR)));
			ServletFileUpload upload = new ServletFileUpload(factory);
			upload.setSizeMax(MAX_UPLOAD_FILE_SIZE);

			List<FileItem> items = upload.parseRequest(request);
			
			for (FileItem item : items) {
				for (Field field : fields) {
					if(field.getName().equals(item.getFieldName())){
						String methodName = "set"
							+ StringUtils.firstLetterToUpcase(field.getName());
						Method method = obj.getClass().getMethod(methodName,
								new Class[] { field.getType() });
						if (field.getType().equals(Integer.class)) {
							Object value = item.getString(Constants.ENCODING);
							if (!StringUtils.isEmpty(value.toString())) {
								method.invoke(this.obj, new Integer[] { Integer
										.parseInt(value.toString()) });
							} else {
								method.invoke(this.obj, new Integer[] { null });
							}
	
						} else if (field.getType().equals(Double.class)) {
							Object value = item.getString(Constants.ENCODING);
							if (value != null && !StringUtils.isEmpty(value.toString())) {
								method.invoke(this.obj, new Double[] { Double
										.parseDouble(value.toString()) });
							} else {
								method.invoke(this.obj, new Double[] { null });
							}
	
						} else if(field.getType().equals(Blob.class)){
							
							Method methodfieldName = obj.getClass().getMethod(methodName + "Name",
									new Class[] { String.class });
							String headPhotoName = System.currentTimeMillis() + StringUtils.getFileExtension(item.getName());
							
							if(item.getSize() > 0){
								method.invoke(this.obj, new Blob[] { Hibernate.createBlob(item.getInputStream()) });
								methodfieldName.invoke(this.obj, new String[] { headPhotoName });
								item.write(new File(UPLOAD_TEMP_REAL_DIR + headPhotoName));
							}else{
								method.invoke(this.obj, new Blob[] { null });
								
								methodfieldName.invoke(this.obj, new String[] { null });
							}
							
						}else {
							Object value = item.getString(Constants.ENCODING);
							method.invoke(this.obj, new Object[] { value });
						}
					}
				}
			}
		} else {
			for (Field field : fields) {
				String methodName = "set"
						+ StringUtils.firstLetterToUpcase(field.getName());
				Method method = obj.getClass().getMethod(methodName,
						new Class[] { field.getType() });
				Object value = request.getParameter(field.getName());
				if (field.getType().equals(Integer.class)) {
					if (!StringUtils.isEmpty(value.toString())) {
						method.invoke(this.obj, new Integer[] { Integer
								.parseInt(value.toString()) });
					} else {
						method.invoke(this.obj, new Integer[] { null });
					}

				} else if (field.getType().equals(Double.class)) {
					if (value != null && !StringUtils.isEmpty(value.toString())) {
						method.invoke(this.obj, new Double[] { Double
								.parseDouble(value.toString()) });
					} else {
						method.invoke(this.obj, new Double[] { null });
					}

				} else if(field.getType().equals(Blob.class)){
					continue;
				}else {
					method.invoke(this.obj, new Object[] { value });
				}
			}
		}
	}

}
